Telegram Group & Telegram Channel
😡 How to: не писать `__init__`

До Python 3.7, если вы хотели создать объект Coordinate(x=1, y=2), приходилось писать:
class Coordinate:
def __init__(self, x: int, y: int):
self.x = x
self.y = y


Это выглядело нормально. Но:
📍 если убрать класс из API — теряется типизация;
📍 если разрешить создавать объект без данных — получаем некорректные объекты;
📍 если задать поля по умолчанию — объект становится мутируемым;
📍 для валидации нужно усложнять структуру.

Главная проблема

__init__ запускает код при каждом создании объекта, что усложняет работу, особенно если нужны побочные действия (например, открытие файла).

Пример проблемного кода:
class FileReader:
def __init__(self, path: str):
self._fd = fileio.open(path)


Вроде удобно. Но:
📍 Вы не можете передать fd напрямую — нужно городить object.__new__.
📍 Тестировать сложно — надо мокать fileio.open.
📍 Если open становится async, вам уже не обойтись __init__.

Ключевая ошибка: связывать создание объекта с побочными эффектами (например, I/O) — это антипаттерн.

Современное решение

1⃣ Используйте @dataclass для объявления:
@dataclass
class FileReader:
_fd: int # или лучше: FileDescriptor


2⃣ Вынесите создание объекта в @classmethod:
from typing import Self

@dataclass
class FileReader:
_fd: int

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path))


Теперь создавайте объект так: FileReader.open("file.txt"), а не через __init__.

Это решение поддерживает:
📍 чистую типизацию
📍 возможность перехода на async
📍 множественные фабрики (from_fd, from_buffer, from_resource, ...)

3⃣ Типизируйте примитивы через NewType:
from typing import NewType
FileDescriptor = NewType("FileDescriptor", int)


Используйте в классе:
@dataclass
class FileReader:
_fd: FileDescriptor

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path)) # пусть возвращает FileDescriptor


Новая практика для классов в Python:
1. Используйте @dataclass.
2. Не пишите __init__ вручную.
3. Добавляйте @classmethod-фабрики (.open(), .from_config(), .from_env()).
4. Используйте NewType.

Это даёт чистый, тестируемый, удобный и расширяемый код.

Библиотека питониста #буст
Please open Telegram to view this post
VIEW IN TELEGRAM



tg-me.com/pyproglib/6772
Create:
Last Update:

😡 How to: не писать `__init__`

До Python 3.7, если вы хотели создать объект Coordinate(x=1, y=2), приходилось писать:

class Coordinate:
def __init__(self, x: int, y: int):
self.x = x
self.y = y


Это выглядело нормально. Но:
📍 если убрать класс из API — теряется типизация;
📍 если разрешить создавать объект без данных — получаем некорректные объекты;
📍 если задать поля по умолчанию — объект становится мутируемым;
📍 для валидации нужно усложнять структуру.

Главная проблема

__init__ запускает код при каждом создании объекта, что усложняет работу, особенно если нужны побочные действия (например, открытие файла).

Пример проблемного кода:
class FileReader:
def __init__(self, path: str):
self._fd = fileio.open(path)


Вроде удобно. Но:
📍 Вы не можете передать fd напрямую — нужно городить object.__new__.
📍 Тестировать сложно — надо мокать fileio.open.
📍 Если open становится async, вам уже не обойтись __init__.

Ключевая ошибка: связывать создание объекта с побочными эффектами (например, I/O) — это антипаттерн.

Современное решение

1⃣ Используйте @dataclass для объявления:
@dataclass
class FileReader:
_fd: int # или лучше: FileDescriptor


2⃣ Вынесите создание объекта в @classmethod:
from typing import Self

@dataclass
class FileReader:
_fd: int

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path))


Теперь создавайте объект так: FileReader.open("file.txt"), а не через __init__.

Это решение поддерживает:
📍 чистую типизацию
📍 возможность перехода на async
📍 множественные фабрики (from_fd, from_buffer, from_resource, ...)

3⃣ Типизируйте примитивы через NewType:
from typing import NewType
FileDescriptor = NewType("FileDescriptor", int)


Используйте в классе:
@dataclass
class FileReader:
_fd: FileDescriptor

@classmethod
def open(cls, path: str) -> Self:
return cls(fileio.open(path)) # пусть возвращает FileDescriptor


Новая практика для классов в Python:
1. Используйте @dataclass.
2. Не пишите __init__ вручную.
3. Добавляйте @classmethod-фабрики (.open(), .from_config(), .from_env()).
4. Используйте NewType.

Это даёт чистый, тестируемый, удобный и расширяемый код.

Библиотека питониста #буст

BY Библиотека питониста | Python, Django, Flask




Share with your friend now:
tg-me.com/pyproglib/6772

View MORE
Open in Telegram


Библиотека питониста | Python Django Flask Telegram | DID YOU KNOW?

Date: |

What is Telegram?

Telegram is a cloud-based instant messaging service that has been making rounds as a popular option for those who wish to keep their messages secure. Telegram boasts a collection of different features, but it’s best known for its ability to secure messages and media by encrypting them during transit; this prevents third-parties from snooping on messages easily. Let’s take a look at what Telegram can do and why you might want to use it.

Библиотека питониста | Python Django Flask from tw


Telegram Библиотека питониста | Python, Django, Flask
FROM USA